package com.etouch.security.controller;

import com.etouch.security.exception.ExceptionEnum;
import com.etouch.security.exception.ProjectException;
import com.etouch.security.pojo.dto.SysUserDTO;
import com.etouch.security.security.smslogin.SmsCodeAuthenticationToken;
import com.etouch.security.service.SysUserService;
import com.etouch.security.util.ResultUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.security.SecurityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.Security;
import java.util.Objects;

import static org.springframework.security.web.context.HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;

/**
 * @author chenyunchang
 * @title
 * @date 2020/10/28 11:10
 * @Description:
 */
@RestController
@RequestMapping
@Slf4j
@Api(tags = "登陆相关接口")
public class LoginController {

    private static final String LOGIN_CODE = "code:login:";

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private StringRedisTemplate redisTemplate;


    @ApiOperation("用户名,密码登陆")
    @PostMapping("/login")
    public ResultUtils<SysUserDTO> login(@RequestParam String username, @RequestParam String password, HttpServletRequest request) {
        SysUserDTO sysUserDTO = sysUserService.getUserByUserName(username);
        if (sysUserDTO == null) {
            throw new ProjectException(ExceptionEnum.USER_NOT_FOUND);
        }
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean matches = bCryptPasswordEncoder.matches(password, sysUserDTO.getPassword());
        if (!matches) {
            throw new ProjectException(ExceptionEnum.USERNAME_OR_PASSWORD_ERRO);
        }
        sysUserDTO.setPassword(null);
        // 系统登录认证
        return ResultUtils.success("登陆成功", sysUserDTO);
    }

    @ApiOperation("手机号, 验证码登陆")
    @PostMapping("/login/phone")
    public ResultUtils<SysUserDTO> loginByPhoneAndCode(String phone, String smsCode, HttpServletRequest request) {
        //security已经错过校验, 这里不再校验验证码
        SysUserDTO sysUserDTO = sysUserService.getUserByPhone(phone);
        if (sysUserDTO == null) {
            throw new ProjectException(ExceptionEnum.USER_NOT_FOUND);
        }
        sysUserDTO.setPassword(null);
        //进行手动security登陆
        UserDetails userDetails = userDetailsService.loadUserByUsername(sysUserDTO.getUsername());
        SmsCodeAuthenticationToken smsCodeAuthenticationToken = new SmsCodeAuthenticationToken(phone, userDetails.getAuthorities());
        Authentication authenticate = authenticationManager.authenticate(smsCodeAuthenticationToken);
        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authenticate);
        HttpSession session = request.getSession(true);
        //在session中存放security context,方便同一个session中控制用户的其他操作
        session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, context);
        return ResultUtils.success("登陆成功", sysUserDTO);
    }
    @ApiOperation("退出登陆")
    @PostMapping("/logout")
    public void logout() {
        log.info("退出登陆成功");
    }

    @ApiOperation("手机号, 验证码登陆(王炜)")
    @PostMapping("/login/phone2")
    public ResultUtils<SysUserDTO> loginByPhoneAndCode2(@RequestParam String phone,@RequestParam String smsCode, HttpServletRequest request) {
        //1. 首先校验验证码
        String redisPhoneCode = redisTemplate.opsForValue().get(LOGIN_CODE);
        if (!smsCode.equals(redisPhoneCode)) {
            throw new ProjectException(400, "验证码错误");
        }
        //1.拿手机号去数据库查找是否有该用户
        SysUserDTO sysUserDTO = sysUserService.getUserByPhone2(phone);
        return ResultUtils.success("登陆成功", sysUserDTO);
    }
}
